home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKitArchive.mbox / Re__MiscMatrix_bugs_.attach / MiscMatrix.m < prev   
Text File  |  1994-07-07  |  16KB  |  677 lines

  1. //
  2. //    MiscMatrix.m -- a class to implement variable-sized matrices
  3. //        Written by Mike Ferris (c) 1994 by Mike Ferris.
  4. //        Modified from original MOKit "MOMatrix" class by Don Yacktman.
  5. //                Version 1.0.  All rights reserved.
  6. //
  7. //        This notice may not be removed from this source code.
  8. //
  9. //    This object is included in the MiscKit by permission from the author
  10. //    and its use is governed by the MiscKit license, found in the file
  11. //    "LICENSE.rtf" in the MiscKit distribution.  Please refer to that file
  12. //    for a list of all applicable permissions and restrictions.
  13. //    
  14.  
  15. // MiscMatrix is a subclass of Matrix that allows independantly sizable
  16. // rows and columns.  Each row can have a different height and each column
  17. // can have a different width.
  18.  
  19. #import <misckit/MiscMatrix.h>
  20. #import <objc/objc-runtime.h>
  21.  
  22. #define CLASS_VERSION         0
  23. #define CLASS_NAME            "MiscMatrix"
  24.  
  25. // These are the private methods we use in MiscMatrix
  26. @interface MiscMatrix(private)
  27.  
  28. - _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone;
  29. - _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col;
  30. - _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row;
  31.  
  32. @end
  33.  
  34. @implementation MiscMatrix
  35.  
  36. + initialize
  37. // Set the class version
  38. {
  39.     if (self == objc_lookUpClass(CLASS_NAME))  {
  40.         [self setVersion:CLASS_VERSION];
  41.     }
  42.     return self;
  43. }
  44.  
  45. - setupStorage:(int)rowsHigh :(int)colsWide
  46. // Set up our storage objects
  47. {
  48.     int i;
  49.     MiscColumnSize newCSize;
  50.     MiscRowSize newRSize;
  51.     
  52.     columnSizes = [[Storage allocFromZone:[self zone]] initCount:0 
  53.                 elementSize:sizeof(MiscColumnSize)
  54.                 description:MISC_COLUMNSIZE_DESC];
  55.     rowSizes = [[Storage allocFromZone:[self zone]] initCount:0 
  56.                 elementSize:sizeof(MiscRowSize)
  57.                 description:MISC_ROWSIZE_DESC];
  58.     
  59.     newCSize.width = cellSize.width;
  60.     newRSize.height = cellSize.height;
  61.     for (i=0; i<colsWide; i++)  {
  62.         newCSize.x = bounds.origin.x + (i*cellSize.width) + 
  63.                     (i*intercell.width);
  64.         [columnSizes addElement:&newCSize];
  65.     }
  66.     for (i=0; i<rowsHigh; i++)  {
  67.         newRSize.y = bounds.origin.y + (i*cellSize.height) + 
  68.                     (i*intercell.height);
  69.         [rowSizes addElement:&newRSize];
  70.     }
  71.     
  72.     return self;
  73. }
  74.  
  75. - initFrame:(const NXRect *)frm mode:(int)aMode prototype:cellId 
  76.             numRows:(int)rowsHigh numCols:(int)colsWide
  77. // Designated initializer override from Matrix.  Sets up our storage stuff.
  78. {
  79.     [super initFrame:frm mode:aMode prototype:cellId numRows:numRows 
  80.                 numCols:numCols];
  81.     
  82.     [self setupStorage:rowsHigh :colsWide];
  83.     
  84.     return self;
  85. }
  86.  
  87. - initFrame:(const NXRect *)frm mode:(int)aMode cellClass:factoryId 
  88.             numRows:(int)rowsHigh numCols:(int)colsWide
  89. // Designated initializer override from Matrix.  Sets up our storage stuff.
  90. {
  91.     [super initFrame:frm mode:aMode cellClass:factoryId numRows:numRows 
  92.                 numCols:numCols];
  93.     
  94.     [self setupStorage:rowsHigh :colsWide];
  95.     
  96.     return self;
  97. }
  98.  
  99. - _Misc_copyRowSizes:rs andColSizes:cs zone:(NXZone *)zone
  100. {
  101.     rowSizes = [rs copyFromZone:zone];
  102.     columnSizes = [cs copyFromZone:zone];
  103.     return self;
  104. }
  105.  
  106. - copyFromZone:(NXZone *)zone
  107. {
  108.     id obj = [super copyFromZone:zone];
  109.     [obj _Misc_copyRowSizes:rowSizes andColSizes:columnSizes zone:zone];
  110.     return obj;
  111. }
  112.  
  113. - free
  114. // free the storage
  115. {
  116.     [columnSizes free];
  117.     [rowSizes free];
  118.     return [super free];
  119. }
  120.  
  121. - _Misc_moveColumnsRightBy:(NXCoord)difference startingAt:(int)col
  122. // A private method used by the methods which cause sizing stuff to change
  123. {
  124.     int i;
  125.  
  126.     if ((col < 0) || (col >= numCols))  {
  127.         return nil;
  128.     }
  129.  
  130.     for (i=col; i<numCols; i++)  {
  131.         MiscColumnSize *cSize;
  132.         cSize = (MiscColumnSize *)[columnSizes elementAt:i];
  133.         if (cSize)  cSize->x += difference;
  134.     }
  135.     return self;
  136. }
  137.  
  138. - _Misc_moveRowsDownBy:(NXCoord)difference startingAt:(int)row
  139. // A private method used by the methods which cause sizing stuff to change
  140. {
  141.     int i;
  142.     
  143.     if ((row < 0) || (row >= numRows))  {
  144.         return nil;
  145.     }
  146.  
  147.     for (i=row; i<numRows; i++)  {
  148.         MiscRowSize *rSize;
  149.         rSize = (MiscRowSize *)[rowSizes elementAt:i];
  150.         if (rSize)  rSize->y += difference;
  151.     }
  152.     return self;
  153. }
  154.  
  155. - setWidth:(NXCoord)newWidth ofCol:(int)col
  156. // This method allows the setting of column widths
  157. {
  158.     NXCoord diff;
  159.     MiscColumnSize *cSize;
  160.     
  161.     if ((col < 0) || (col >= numCols))  {
  162.         return nil;
  163.     }
  164.  
  165.     cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  166.     diff = newWidth - cSize->width;
  167.     cSize->width = newWidth;
  168.     [self _Misc_moveColumnsRightBy:diff startingAt:col+1];
  169.     
  170.     return self;
  171. }
  172.  
  173. - setHeight:(NXCoord)newHeight ofRow:(int)row
  174. // This method allows the setting of row heights
  175. {
  176.     NXCoord diff;
  177.     MiscRowSize *rSize;
  178.     
  179.     if ((row < 0) || (row >= numRows))  {
  180.         return nil;
  181.     }
  182.  
  183.     rSize = (MiscRowSize *)[rowSizes elementAt:row];
  184.     diff = newHeight - rSize->height;
  185.     rSize->height = newHeight;
  186.     [self _Misc_moveRowsDownBy:diff startingAt:row+1];
  187.         
  188.     return self;
  189. }
  190.  
  191. - sizeToCells
  192. // Resize the matrix to the proper size to fit all our cells.
  193. {
  194.     NXRect rect;
  195.     MiscColumnSize *cSize;
  196.     MiscRowSize *rSize;
  197.     
  198.     [self getFrame:&rect];
  199.     
  200.     if (numCols == 0)  {
  201.         rect.size.width = 0.0;
  202.     }  else  {
  203.         cSize = (MiscColumnSize *)[columnSizes lastElement];
  204.         rect.size.width = cSize->x + cSize->width - bounds.origin.x;
  205.     }
  206.  
  207.     if (numRows == 0)  {
  208.         rect.size.height = 0.0;
  209.     }  else  {
  210.         rSize = (MiscRowSize *)[rowSizes lastElement];
  211.         rect.size.height = rSize->y + rSize->height - bounds.origin.y;
  212.     }
  213.     
  214.     [self setFrame:&rect];
  215.  
  216.     return self;
  217. }
  218.  
  219. - renewRows:(int)newRows cols:(int)newCols
  220. // Makes sure to keep our storage objects in synch with everything else.
  221. {
  222.     MiscColumnSize newCSize, *cSize;
  223.     MiscRowSize newRSize, *rSize;
  224.     int i;
  225.     
  226.     // Remove any storage elements past the new number of cols
  227.     for (i=numCols-1; i>=newCols; i--)  {
  228.         [columnSizes removeLastElement];
  229.     }
  230.     // Add any needed new storage elements to get up to the new number of cols
  231.     for (i=numCols; i<newCols; i++)  {
  232.         if (i==0)  {
  233.             newCSize.x = bounds.origin.x;
  234.         }  else  {
  235.             cSize = (MiscColumnSize *)[columnSizes lastElement];
  236.             newCSize.x = cSize->x + cSize->width + intercell.width;
  237.         }
  238.         newCSize.width = cellSize.width;
  239.         [columnSizes addElement:&newCSize];
  240.     }
  241.  
  242.     // Remove any storage elements past the new number of rows
  243.     for (i=numRows-1; i>=newRows; i++)  {
  244.         [rowSizes removeLastElement];
  245.     }
  246.     // Add any needed new storage elements to get up to the new number of rows
  247.     for (i=numRows; i<newRows; i++)  {
  248.         if (i==0)  {
  249.             newRSize.y = bounds.origin.y;
  250.         }  else  {
  251.             rSize = (MiscRowSize *)[rowSizes lastElement];
  252.             newRSize.y = rSize->y + rSize->height + intercell.height;
  253.         }
  254.         newRSize.height = cellSize.height;
  255.         [rowSizes addElement:&newRSize];
  256.     }
  257.     
  258.     [super renewRows:newRows cols:newCols];
  259.     
  260.     return self;
  261. }
  262.  
  263.  
  264. - insertColAt:(int)col
  265. // Keep the storage in synch
  266. {
  267.     MiscColumnSize newCSize, *cSize;
  268.     
  269.     if (col < 0)  {
  270.         return nil;
  271.     }
  272.     
  273.     if (col <= numCols)  {
  274.         [super insertColAt:col];
  275.  
  276.         if (col > 0)  {
  277.             cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  278.             newCSize.x = cSize->x;
  279.         }  else  {
  280.             newCSize.x = bounds.origin.x;
  281.         }
  282.         newCSize.width = cellSize.width;
  283.         [columnSizes insertElement:&newCSize at:col];
  284.         
  285.         [self _Misc_moveColumnsRightBy:newCSize.width + intercell.width 
  286.                     startingAt:col+1];
  287.     }  else  {
  288.         return nil;
  289.     }
  290.     return self;
  291. }
  292.  
  293. - insertRowAt:(int)row
  294. // Keep the storage in synch
  295. {
  296.     MiscRowSize newRSize, *rSize;
  297.     
  298.     if ((row < 0) || (row > numRows))
  299.     return nil;
  300.     
  301.     if (row == numRows)
  302.     {
  303.     if (numRows == 0)
  304.         newRSize.y = bounds.origin.y;
  305.     else
  306.     {
  307.         rSize = (MiscRowSize *)[rowSizes elementAt:row-1];
  308.         newRSize.y = rSize->y + rSize->height + intercell.height;
  309.     }
  310.     }
  311.     else
  312.     {
  313.     rSize = (MiscRowSize *)[rowSizes elementAt:row];
  314.     newRSize.y = rSize->y;
  315.     }
  316.     newRSize.height = cellSize.height;
  317.     [super insertRowAt:row];
  318.     [rowSizes insertElement:&newRSize at:row];
  319.         
  320.     [self _Misc_moveRowsDownBy:newRSize.height + intercell.height 
  321.             startingAt:row+1
  322.     ];
  323.     return self;
  324. }
  325.  
  326. - removeColAt:(int)col andFree:(BOOL)flag
  327. // Keep the storage in synch
  328. {
  329.     MiscColumnSize *cSize;
  330.     NXCoord diff;
  331.     
  332.     if ((col >= numCols) || (col < 0))  {
  333.         return nil;
  334.     }
  335.     
  336.     [super removeColAt:col andFree:flag];
  337.  
  338.     cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  339.     diff = cSize->width;
  340.     [columnSizes removeElementAt:col];
  341.     [self _Misc_moveColumnsRightBy:0.0 - diff - intercell.width
  342.             startingAt:col];
  343.     
  344.     return self;
  345. }
  346.  
  347. - removeRowAt:(int)row andFree:(BOOL)flag
  348. // Keep the storage in synch
  349. {
  350.     MiscRowSize *rSize;
  351.     NXCoord diff;
  352.     
  353.     if ((row >= numRows) || (row < 0))  {
  354.         return nil;
  355.     }
  356.  
  357.     [super removeRowAt:row andFree:flag];
  358.  
  359.     rSize = (MiscRowSize *)[rowSizes elementAt:row];
  360.     diff = rSize->height;
  361.     [rowSizes removeElementAt:row];
  362.     [self _Misc_moveRowsDownBy:0.0 - diff - intercell.height startingAt:row];
  363.     
  364.     return self;
  365. }
  366.  
  367. - drawSelf:(const NXRect *)rects:(int)rectCount
  368. // We do our own drawing because we need to draw our cells in diverse 
  369. // rectangles
  370. {
  371.     int i, j;
  372.     NXRect cFrm;
  373.     
  374.     [window disableFlushWindow];
  375.     
  376.     // the background (if any)
  377.     if (backgroundGray != -1.0)  {
  378.         PSsetgray(backgroundGray);
  379.         if (rectCount==1)  {
  380.             NXRectFill(&(rects[0]));
  381.         }  else  {
  382.             NXRectFill(&(rects[1]));
  383.             NXRectFill(&(rects[2]));
  384.         }
  385.     }
  386.     
  387.     // The cells
  388.     for (i=0; i<numRows; i++)  {
  389.         for (j=0; j<numCols; j++)  {
  390.             [self getCellFrame:&cFrm at:i:j];
  391.             if (rectCount == 1)  {
  392.                 if (NXIntersectsRect(&(rects[0]), &cFrm))  {
  393.                     [self drawCellAt:i:j];
  394.                 }
  395.             }  else  {
  396.                 if ((NXIntersectsRect(&(rects[1]), &cFrm)) || 
  397.                             (NXIntersectsRect(&(rects[2]), &cFrm)))  {
  398.                     [self drawCellAt:i:j];
  399.                 }
  400.             }
  401.         }
  402.     }
  403.  
  404.     [window reenableFlushWindow];
  405.     [window flushWindow];
  406.     
  407.     return self;
  408. }
  409.  
  410. - getCellFrame:(NXRect *)theRect at:(int)row:(int)col
  411. // Calculate and return the rect used to display the cell at the given
  412. // row and column
  413. {
  414.     MiscColumnSize *cSize;
  415.     MiscRowSize *rSize;
  416.     
  417.     if (col < numCols)  {
  418.         cSize = (MiscColumnSize *)[columnSizes elementAt:col];
  419.         theRect->origin.x = cSize->x;
  420.         theRect->size.width = cSize->width;
  421.     }  else  {
  422.         int num = col - numCols;
  423.         
  424.         cSize = (MiscColumnSize *)[columnSizes lastElement];
  425.         theRect->origin.x = cSize->x +
  426.                     (num * (cellSize.width + intercell.width));
  427.         theRect->size.width = cellSize.width;
  428.     }
  429.     
  430.     if (row < numRows)  {
  431.         rSize = (MiscRowSize *)[rowSizes elementAt:row];
  432.         theRect->origin.y = rSize->y;
  433.         theRect->size.height = rSize->height;
  434.     }  else  {
  435.         int num = row - numRows;
  436.         
  437.         rSize = (MiscRowSize *)[rowSizes lastElement];
  438.         theRect->origin.y = rSize->y +
  439.                     (num * (cellSize.height + intercell.height));
  440.         theRect->size.height = cellSize.height;
  441.     }
  442.     
  443.     return self;
  444. }
  445.  
  446. - getRow:(int *)row andCol:(int *)col forPoint:(const NXPoint *)aPoint
  447. // Calculate the row and column of the cell which contains the given point
  448. {
  449.     MiscColumnSize *cSize;
  450.     MiscRowSize *rSize;
  451.     int i;
  452.     
  453.     *row = -1;
  454.     *col = -1;
  455.     if ((aPoint->x < bounds.origin.x) || 
  456.                 (aPoint->x > bounds.origin.x + bounds.size.width) || 
  457.                 (aPoint->y < bounds.origin.y) || 
  458.                 (aPoint->y > bounds.origin.y + bounds.size.height))  {
  459.         return nil;
  460.     }
  461.     for (i=0; i<numCols; i++)  {
  462.         cSize = (MiscColumnSize *)[columnSizes elementAt:i];
  463.         if ((aPoint->x >= cSize->x) && 
  464.                     (aPoint->x <= cSize->x + cSize->width))  {
  465.             *col = i;
  466.             break;
  467.         }
  468.     }
  469.     for (i=0; i<numRows; i++)  {
  470.         rSize = (MiscRowSize *)[rowSizes elementAt:i];
  471.         if ((aPoint->y >= rSize->y) && 
  472.                     (aPoint->y <= rSize->y + rSize->height))  {
  473.             *row = i;
  474.             break;
  475.         }
  476.     }
  477.     return ((*row == -1) || (*col == -1)) ? nil : self;
  478. }
  479.  
  480. - setIntercell:(const NXSize *)aSize
  481. // Keep the storage in synch
  482. {
  483.     NXCoord xDiff = aSize->width - intercell.width;
  484.     NXCoord yDiff = aSize->height - intercell.height;
  485.     MiscRowSize *rSize;
  486.     MiscColumnSize *cSize;
  487.     int i;
  488.     
  489.     for (i=1; i<numRows; i++)  {
  490.         rSize = (MiscRowSize *)[rowSizes elementAt:i];
  491.         rSize->y += (yDiff * i);
  492.     }
  493.     for (i=1; i<numCols; i++)  {
  494.         cSize = (MiscColumnSize *)[columnSizes elementAt:i];
  495.         cSize->x += (xDiff * i);
  496.     }
  497.     
  498.     return [super setIntercell:aSize];
  499. }
  500.  
  501.  
  502. - write:(NXTypedStream *)typedStream
  503. // Write our ivars
  504. {
  505.     [super write:typedStream];
  506.     NXWriteObject(typedStream, columnSizes);
  507.     NXWriteObject(typedStream, rowSizes);
  508.     return self;
  509. }
  510.  
  511. - read:(NXTypedStream *)typedStream
  512. // Read our ivars
  513. {
  514.     int classVersion;
  515.  
  516.     [super read:typedStream];
  517.     
  518.     classVersion = NXTypedStreamClassVersion(typedStream, CLASS_NAME);
  519.     
  520.     switch (classVersion)  {
  521.         case 0:        // First version.
  522.             columnSizes = NXReadObject(typedStream);
  523.             rowSizes = NXReadObject(typedStream);
  524.             break;
  525.         default:
  526.             NXLogError("[%s read:] class version %d cannot read "
  527.                         "instances archived with version %d", 
  528.                         CLASS_NAME, CLASS_VERSION, classVersion);
  529.             [self setupStorage:numRows :numCols];
  530.             break;
  531.     }
  532.     return self;
  533. }
  534.  
  535.  
  536. // ********************Overridden private methods***********************
  537. // *****************that I'm going to hell for using********************
  538.  
  539. // These methods are used by Matrix's mouseDown:.  Doing the whole 
  540. // mouseDown: method over would have been a royal pain in the butt, 
  541. // so I cheated.
  542.  
  543.  
  544. - (BOOL)_mouseHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
  545. {
  546.     NXPoint    point;
  547.     id        ret;
  548.  
  549.     point = *forpoint;
  550.     [self convertPoint:&point fromView:nil];
  551.     ret = [self getRow:row andCol:col forPoint:&point];
  552.  
  553.     if (ret == nil)
  554.         return NO;
  555.     return YES;
  556. }
  557.  
  558. - (BOOL)_loopHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
  559. {
  560.     NXPoint    point;
  561.     id        ret;
  562.  
  563.     point = *forpoint;
  564.     [self convertPoint:&point fromView:nil];
  565.     ret = [self getRow:row andCol:col forPoint:&point];
  566.  
  567.     if (ret == nil)
  568.         return NO;
  569.     return YES;
  570. }
  571.  
  572. - (BOOL)_radioHit:(const NXPoint *)forpoint row:(int *)row col:(int *)col
  573. {
  574.     NXPoint    point;
  575.     id        ret;
  576.  
  577.     point = *forpoint;
  578.     [self convertPoint:&point fromView:nil];
  579.     ret = [self getRow:row andCol:col forPoint:&point];
  580.  
  581.     if (ret == nil)
  582.         return NO;
  583.     return YES;
  584. }
  585.  
  586. - sizeRowsToFitCells
  587. {
  588.     NXRect    veryBig;
  589.     NXSize    size;
  590.     NXRect    myFrame;
  591.     NXCoord    maxHeight;
  592.     NXCoord    offset = 0.0;
  593.     MiscRowSize    *rSize;
  594.     int        i,j;
  595.     
  596.     veryBig.size.width = cellSize.width;
  597.     veryBig.size.height = MAXFLOAT;
  598.     
  599.     [self getFrame:&myFrame];
  600.     for (i = 0; i < numRows; i++)
  601.     {
  602.     maxHeight = 0.0;
  603.     rSize = (MiscRowSize *)[rowSizes elementAt:i];
  604.     rSize->y = offset;
  605.     for (j = 0; j < numCols; j++)
  606.     {
  607.         [[self cellAt:i :j] calcCellSize:&size inRect:&veryBig];
  608.         if (size.height > maxHeight)
  609.         maxHeight = size.height;
  610.     }
  611.     rSize->height = maxHeight;
  612.     offset += maxHeight + intercell.height;
  613.     }
  614.     
  615.     myFrame.size.height = offset;
  616.     [self setFrame:&myFrame];
  617.     return self;
  618. }
  619.     
  620.  
  621. - sizeTo:(NXCoord)width :(NXCoord)height
  622. {
  623.     NXRect    oldFrame;
  624.     NXCoord    dx, dy;
  625.     float    sx, sy;
  626.     
  627.     printf ("sizeTo\n");
  628.     [self getFrame:&oldFrame];
  629.     
  630.     [super sizeTo:width :height];
  631.  
  632.     dx = width - oldFrame.size.width;
  633.     dy = height - oldFrame.size.height;
  634.  
  635.     if ([self doesAutosizeCells] && (numRows > 0) && (numCols > 0))
  636.     {
  637.     NXCoord        offset;
  638.     int        i;
  639.     MiscRowSize    *rSize;
  640.     MiscColumnSize    *cSize;
  641.     
  642.     sx = 1 + (dx/(oldFrame.size.width - (numRows - 1)*intercell.width));
  643.     sy = 1 + (dy/(oldFrame.size.height - (numCols - 1)*intercell.height));
  644.     
  645.     for (i=0, offset = 0.0; i < numRows; i++)
  646.     {
  647.         rSize = (MiscRowSize *)[rowSizes elementAt:i];
  648.         rSize->y = offset;
  649.         rSize->height *= floor(sy+0.5);
  650.         offset += rSize->height + intercell.height;
  651.     }
  652.     
  653.     for (i=0, offset = 0.0; i < numCols; i++)
  654.     {
  655.         cSize = (MiscColumnSize *)[columnSizes elementAt:i];
  656.         cSize->x = offset;
  657.         cSize->width *= sx;
  658.         offset += cSize->width + intercell.width;
  659.     }
  660.     }
  661.     return self;
  662. }
  663.  
  664.  
  665. @end
  666.  
  667. @implementation Storage(MiscLastElementCategory)
  668.     
  669. - (void *)lastElement
  670. // A little shortcut
  671. {
  672.     return [self elementAt:numElements-1];
  673. }
  674.     
  675. @end
  676.  
  677.